home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / GameKit / gamekit-1 / GKActor.m < prev    next >
Text File  |  1995-06-12  |  6KB  |  193 lines

  1.  
  2. // Handles moving and rendering various moving objects.
  3.  
  4. #import <gamekit/gamekit.h>
  5. #import <stdio.h>
  6.  
  7. @implementation GKActor
  8.  
  9. - init                // initialize the new instance vars
  10. {    // You need to override this to set state and maxFrames at the very least
  11.     [super init];
  12.     NX_X(&boundingBox) = 0;
  13.     NX_Y(&boundingBox) = 0;
  14.     NX_HEIGHT(&boundingBox) = GK_DEFAULT_ACTOR_WIDTH;
  15.     NX_WIDTH(&boundingBox) = GK_DEFAULT_ACTOR_HEIGHT;
  16.     GK_CLEAR_VECTOR(&nextLocation);
  17.     GK_CLEAR_VECTOR(&lastLocation);
  18.     GK_CLEAR_VECTOR(&lastDrawnLocation);
  19.     maxFrames = (int *)malloc(sizeof(int));
  20.     maxFrames[0] = 0; maxSeries = 1; series = 0;
  21.     frame = 0; cycles = 0; state = GK_DEAD_ACTOR;
  22.     renderedImage = nil; drawingLevel = GK_DYNAMIC_ACTOR;
  23.     return self;
  24. }
  25.  
  26. - (int)drawingLevel { return drawingLevel; }
  27. - setDrawingLevel:(int)aLevel { drawingLevel = aLevel; return self; }
  28. - stage { return stage; }
  29.  
  30. - setStage:aStage { // ***** probably ought to make sure we're not on any other stage!
  31.     stage = aStage;
  32.     return self;
  33. }
  34.  
  35. - leaveTheStage
  36. {
  37.     [stage removeActor:self ofType:drawingLevel];
  38.     return self;
  39. }
  40.  
  41. - setSize:(const NXSize *)aSize
  42.         // set the actor's size (enclosing frame in image)
  43. {
  44.     GK_COPY_SIZES(&(boundingBox.size), aSize);
  45.     return self;
  46. }
  47.  
  48. - setRenderedImage:anImage    // set the bitmap image used to render
  49. {    // we don't free an old image, if it exists.  This is because others
  50.     // might also be using the image.  What I should do is a reference
  51.     // counting image *****
  52.     renderedImage = anImage;
  53.     return self;
  54. }
  55.  
  56. - setSeries:(int)anInt        // set the animation series (row) to use in bitmap
  57. {
  58.     if (anInt >= maxSeries) return nil;    // only change to a valid series number
  59.     series = anInt;
  60.     return self;
  61. }
  62.  
  63. - setMaxFrames:(const int *)anIntArray count:(int)anInt    // array indexed by
  64.         // series number; gives the number of frames in the series
  65. {    // This could possibly be incorporated into an "Array" object, perhaps
  66.     // one which does reference counting. *****
  67.     int i;
  68.     free(maxFrames); maxFrames = (int *)malloc(sizeof(int) * anInt);
  69.     for (i=0; i<anInt; i++) maxFrames[i] = anIntArray[i];
  70.     maxSeries = anInt;
  71.     return self;
  72. }
  73.  
  74. - move:sender                // Move the Actor one animation frame
  75. {    // you must override this and put something here
  76.     // alter the nextLocation vector to move the actor.
  77.     return self;
  78. }
  79.  
  80. - (int)collisionType    // called to determine which type of collision
  81.                         // detection to use with this actor
  82. {    // override to change type... default is the bounding box
  83.     return GK_RECTANGLE_SHAPE;
  84. }
  85.  
  86. - (void *)shapeStruct    // if you change the collision type, you must
  87. {    // return a pointer to an appropriate structure defining the shape
  88.     return (&boundingBox);    // Note that if you call this method, do NOT
  89.     // alter the boundingBox returned!  It will cause all sorts of havoc!
  90. }
  91.  
  92. - collidedWith:anActor    // called when it is detected that we hit something
  93. {    // you should override to do something about the hit, if necessary
  94.     return self;
  95. }
  96.  
  97. - lastAt:(NXPoint *)aPoint    // called to find out where actor was
  98. {
  99.     GK_COPY_VECTORS(aPoint, &lastLocation);
  100.     return self;
  101. }
  102.  
  103. - lastDrawnAt:(NXPoint *)aPoint    // called to find out where actor was
  104. {
  105.     GK_COPY_VECTORS(aPoint, &lastDrawnLocation);
  106.     return self;
  107. }
  108.  
  109. - at:(NXPoint *)aPoint    // called to find out where actor was
  110. {
  111.     GK_COPY_VECTORS(aPoint, &GK_location);
  112.     return self;
  113. }
  114.  
  115. - getBoundingBox:(NXRect *)box
  116. {
  117.     GK_COPY_RECT(box, &boundingBox);
  118.     return self;
  119. }
  120.  
  121. - (int)series { return series; } // the series we're currently using
  122. - (int)frame  { return frame;  } // the next frame that will be drawn
  123.  
  124. - moveOneFrame    // moves the actor along; accessed via renderAt::move:
  125. {
  126.     // flag movement; we won't redraw if no movement...
  127.     if ((GK_VECTOR_X(&GK_location) != GK_VECTOR_X(&nextLocation)) ||
  128.         (GK_VECTOR_Y(&GK_location) != GK_VECTOR_Y(&nextLocation)))
  129.         movedThisFrame = YES;
  130.     GK_COPY_VECTORS(&GK_location, &nextLocation);
  131.     GK_COPY_VECTORS(&lastLocation, &GK_location);
  132.     return self;
  133. }
  134.  
  135. - eraseInDirtPile:dirtPile
  136. {    // pass our most recent dirty rect to the DirtPile...
  137.     [dirtPile addRegion:GK_VECTOR_X(&lastDrawnLocation)
  138.                        :GK_VECTOR_Y(&lastDrawnLocation)
  139.                        :boundingBox.size.width
  140.                        :boundingBox.size.height];
  141.     return self;
  142. }
  143.  
  144. - markInDirtPile:dirtPile    // same as above but called at different times
  145. {    // pass our most recent dirty rect to the DirtPile...
  146.     [dirtPile addRegion:GK_VECTOR_X(&lastDrawnLocation)
  147.                        :GK_VECTOR_Y(&lastDrawnLocation)
  148.                        :boundingBox.size.width
  149.                        :boundingBox.size.height];
  150.     return self;
  151. }
  152.  
  153. - renderAt:(NXPoint *)offset move:(BOOL)moveOk withDirtPile:dirtPile
  154.         // draw actor; lock focus on view that gets the actor before call
  155. {        // this should be overridden by the actor subclass
  156.     NXPoint zero = { 0.0, 0.0 };
  157.     if (state == GK_DEAD_ACTOR) return self;    // we're dead, nothing to do
  158.     if (moveOk) [self moveOneFrame];
  159.     GK_COPY_VECTORS(&lastDrawnLocation, &GK_location); // we need to track
  160.         // this so we can do erase properly
  161.     if (movedThisFrame) {    // handle the drawing if need to redraw.
  162.         if (offset) [self drawActorWithOffset:offset];
  163.         else [self drawActorWithOffset:&zero];
  164.         // mark the drawn area as dirty
  165.         [self markInDirtPile:dirtPile];
  166.         movedThisFrame = NO;
  167.     }
  168.     [self updateDrawingState]; // we update _even_ if no movement;
  169.         // if you object is stationary, but changes shape a lot, then
  170.         // you should set the movedThisFrame flag in this method!
  171.     return self;
  172. }
  173.  
  174. - drawActorWithOffset:(NXPoint *)offset    // draw the actor
  175. {    // 90% of the time you'll override this completely
  176.     NXRect from = { { frame * NX_WIDTH(&boundingBox),
  177.                             series * NX_HEIGHT(&boundingBox) },
  178.                     { NX_WIDTH(&boundingBox), NX_HEIGHT(&boundingBox) } };
  179.     NXPoint pos = { NX_X(&boundingBox) + GK_VECTOR_X(offset),
  180.                     NX_Y(&boundingBox) + GK_VECTOR_Y(offset) };
  181.     [renderedImage composite:NX_SOVER fromRect:&from toPoint:&pos];
  182.     return self;
  183. }
  184.  
  185. - updateDrawingState    // change the internal state machine (ie. advance
  186. {    // frames, etc.  This will also
  187.     cycles++;
  188.     frame++; if (frame >= maxFrames[series]) frame = 0;
  189.     return self;
  190. }
  191.  
  192. @end
  193.